package com.mmall.user.provider.config;

import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.filter.logging.Log4j2Filter;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.google.common.collect.Lists;
import io.seata.rm.datasource.DataSourceProxy;
import io.seata.spring.annotation.GlobalTransactionScanner;
import io.shardingsphere.core.api.MasterSlaveDataSourceFactory;
import io.shardingsphere.core.api.config.MasterSlaveRuleConfiguration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * TODO - 将硬编码配置化
 * @author hejianglong
 * @date 2019/10/23
 */
@ConditionalOnClass
@Configuration
@MapperScan(basePackages = "com.mmall.user.provider.dao", sqlSessionFactoryRef = "mallSqlSessionFactory")
public class DBConfig {

    private final String MASTER_DATA_SOURCE = "masterDataSource";

    private final String SLAVE_1_DATA_SOURCE = "slave1DataSource";

    private final String MASTER_SLAVE = "dbMasterSlave";

    @Value("${spring.application.name}")
    private String applicationId;

    @Value("${seata.tx-service-group}")
    private String txServiceGroup;

    @Value("${mybatis-plus.type-aliases-package}")
    private String mybatisTypeAliasesPackage;

    /**
     * 记录 druid-sql.log 日志
     * @return
     */
    @Bean
    public Log4j2Filter log4j2Filter() {
        Log4j2Filter log4j2Filter = new Log4j2Filter();
        log4j2Filter.setStatementExecutableSqlLogEnable(true);
        log4j2Filter.setResultSetLogEnabled(false);
        log4j2Filter.setConnectionLogEnabled(false);
        log4j2Filter.setStatementLogEnabled(true);
        return log4j2Filter;
    }

    @Bean
    public StatFilter statFilter() {
        StatFilter statFilter = new StatFilter();
        statFilter.setSlowSqlMillis(200);
        statFilter.setLogSlowSql(true);
        return statFilter;
    }

    @Bean
    @ConfigurationProperties("spring.datasource")
    public DruidDataSource druidDataSource() {
        DruidDataSource druidDataSource = new DruidDataSource();
        List<Filter> filter = new ArrayList<>();
        filter.add(log4j2Filter());
        filter.add(statFilter());
        druidDataSource.setProxyFilters(filter);
        return druidDataSource;
    }

    @Bean(SLAVE_1_DATA_SOURCE)
    @ConfigurationProperties("spring.slave1.datasource")
    public DruidDataSource slave1DruidDataSource() {
        DruidDataSource druidDataSource = new DruidDataSource();
        List<Filter> filter = new ArrayList<>();
        filter.add(log4j2Filter());
        filter.add(statFilter());
        druidDataSource.setProxyFilters(filter);
        return druidDataSource;
    }

    @Bean(name = MASTER_DATA_SOURCE)
    public DataSource dataSource() {
        DruidDataSource druidDataSource = druidDataSource();
        return new DataSourceProxy(druidDataSource);
    }

    @Bean(MASTER_SLAVE)
    public DataSource masterSlave(@Qualifier(MASTER_DATA_SOURCE) DataSource masterDataSource, @Qualifier(SLAVE_1_DATA_SOURCE) DataSource slaveDataSource) throws SQLException {
        Map<String, DataSource> dataSourceMap = new HashMap<>();
        dataSourceMap.put(MASTER_DATA_SOURCE, masterDataSource);
        dataSourceMap.put(SLAVE_1_DATA_SOURCE, slaveDataSource);
        MasterSlaveRuleConfiguration ruleConfiguration = new MasterSlaveRuleConfiguration(MASTER_SLAVE, MASTER_DATA_SOURCE, Lists.newArrayList(SLAVE_1_DATA_SOURCE));
        return MasterSlaveDataSourceFactory.createDataSource(dataSourceMap, ruleConfiguration, new ConcurrentHashMap());
    }

    @Bean("mallSqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier(MASTER_SLAVE) DataSource dataSource) throws Exception {
        MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
        sqlSessionFactoryBean.setTypeAliasesPackage(mybatisTypeAliasesPackage);
        return sqlSessionFactoryBean.getObject();
    }

    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        // 设置请求的页面大于最大页后操作， true调回到首页，false 继续请求  默认false
        // paginationInterceptor.setOverflow(false);
        // 设置最大单页限制数量，默认 500 条，-1 不受限制
        // paginationInterceptor.setLimit(500);
        return paginationInterceptor;
    }

    @Bean
    public GlobalTransactionScanner globalTransactionScanner() {
        return new GlobalTransactionScanner(applicationId, txServiceGroup);
    }

    @Bean
    @ConditionalOnMissingBean
    public ServletRegistrationBean druidServlet() {
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");

        //白名单：
        //servletRegistrationBean.addInitParameter("allow","");
        //IP黑名单 (存在共同时，deny优先于allow) : 如果满足deny的话提示:Sorry, you are not permitted to view this page.
        // servletRegistrationBean.addInitParameter("deny","");
        //登录查看信息的账号密码, 用于登录Druid监控后台
        servletRegistrationBean.addInitParameter("loginUsername", "admin");
        servletRegistrationBean.addInitParameter("loginPassword", "admin");
        //是否能够重置数据.
        servletRegistrationBean.addInitParameter("resetEnable", "true");
        return servletRegistrationBean;
    }

    @Bean
    @ConditionalOnMissingBean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new WebStatFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        return filterRegistrationBean;
    }
}
